
import java.util.List;
import java.util.ArrayList;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Edvin
 */
public class U {
	static int getMaxLen(String[] s){
		int max = 0;
		for(int n = 0; n < s.length; n++)
			if(max < s[n].length())
				max = s[n].length();
		return max;
	}

	/*
	 * (space) : tom
	 * # : vägg
	 * @ : spelaren
	 * . : målet
	 * $ : block
	 * * : block på mål
	 *
	 * c : korridor
	 * q : hörn
	 * e : slutet av en korridor, (2*hörn + korridor)
	 *
	 */
	
	static String boardToFlatString(Board board, GameState gs, boolean showExtra){
		String s = "";
		for(int r = 0; r < board.mCellRows; r++){
			for(int c = 0; c < board.mCellCols; c++){
				byte b = board.mCell[r*board.mCellCols + c];
				byte g = gs.At(new int[]{r,c});
				if(r>0 && c==0){
					s+="|";
				}
				if(Board.isInvalid(b)){
					s+=" ";
				}else if(Board.isWall(b)){
					s+="#";
				}else if(GameState.isPlayer(g)){
					if(Board.isGoal(b) && showExtra){
						s+="P";// not standard
					}else{
						s+="@";
					}
				}else if(Board.isGoal(b)){
					if(GameState.isBlock(g)){
						s+="*";
					}else{
						s+=".";
					}
				}else if(GameState.isBlock(g)){
					s+="$";
				}else if(Board.isEmpty(b)){
					if(Board.isCorner(b) && Board.isCorridor(b) && showExtra){
						s+="e";// not standard
					}else if(Board.isCorner(b) && showExtra){
						s+="q";// not standard
					}else if(Board.isCorridor(b) && showExtra){
						s+="c";// not standard
					}else{
						s+=" ";
					}
				}else{
					pr("WTF?!");
				}
			}
		}
		return s;
	}

	static void pr(List<Move> lm, String orginalFlatBoard, boolean showExtra){
		GameState gs = new GameState();
		Board b2 = new Board(orginalFlatBoard, gs);
		prB(boardToFlatString(b2, gs, showExtra));
		for(int i = 0; i < lm.size(); i++){
			gs.doMove(b2, lm.get(i));
			pr("\n\n");
			prB(boardToFlatString(b2, gs, showExtra));
		}
	}

	static void prB(String flatBoard){
		String[] segments = flatBoard.split("\\|");
		for(String segment : segments){
			pr(segment);
		}
	}

	static void prBoardSet(List<Move> lm, String orginalFlatBoard, boolean showExtra, int boardsPerRow){
		GameState gs = new GameState();
		Board b2 = new Board(orginalFlatBoard, gs);

		int rows = (int)(Math.ceil((double)((double)(lm.size())/(double)boardsPerRow)));
//		pr("rows: "+rows+"	lm.size():"+lm.size()+"	boardsPerRow:"+boardsPerRow+"	l/b:"+((double)lm.size()/boardsPerRow));
		String[][] s = new String[rows][b2.mCellRows];
		emptyStrings(s);
		for(int r = 0; r < rows; r++){
			for(int c = 0; c < Math.min(boardsPerRow,lm.size() - r*boardsPerRow); c++){
				gs.doMove(b2, lm.get(r*boardsPerRow + c));
				boardToStrings(s[r], b2, gs, showExtra);
			}
		}
		pr(s);
	}
	static void pr(String[][] s){
		for(int r = 0; r < s.length; r++){
			for(int c = 0; c < s[r].length; c++){
				pr(s[r][c]);
			}
			pr("\n");
		}
	}

	static void boardToStrings(String[] s, Board board, GameState gs, boolean showExtra){
//		String[] s = new String[board.mCellRows];
		for(int r = 0; r < s.length; r++){
			for(int c = 0; c < board.mCellCols; c++){
				byte b = board.mCell[r*board.mCellCols + c];
				byte g = gs.At(new int[]{r,c});
				if(c==0){
					s[r]+="	";
				}
				if(Board.isInvalid(b)){
					s[r]+=" ";
				}else if(Board.isWall(b)){
					s[r]+="#";
				}else if(GameState.isPlayer(g)){
					if(Board.isGoal(b) && showExtra){
						s[r]+="P";// not standard
					}else{
						s[r]+="@";
					}
				}else if(Board.isGoal(b)){
					if(GameState.isBlock(g)){
						s[r]+="*";
					}else{
						s[r]+=".";
					}
				}else if(GameState.isBlock(g)){
					s[r]+="$";
				}else if(Board.isEmpty(b)){
					if(Board.isCorner(b) && Board.isCorridor(b) && showExtra){
						s[r]+="e";// not standard
					}else if(Board.isCorner(b) && showExtra){
						s[r]+="q";// not standard
					}else if(Board.isCorridor(b) && showExtra){
						s[r]+="c";// not standard
					}else if(Board.isWallX(b) && showExtra){
						s[r]+="x";// not standard
					}else if(Board.isWallY(b) && showExtra){
						s[r]+="y";// not standard
					}else{
						s[r]+=" ";
					}
				}else{
					pr("WTF?!");
				}
			}
		}
//		return s;
	}

// prints out all types of a byte
	static void whatAmI_Board(byte b){
		pr("\n===== WHAT AM I? =====");
		if(Board.isInvalid(b)){
			pr("INVALID");
		}
		if(Board.isEmpty(b)){
			pr("EMPTY");
		}
		if(Board.isWall(b)){
			pr("WALL");
		}
//		if(Board.isPlayer(b)){
//			pr("PLAYER");
//		}
		if(Board.isGoal(b)){
			pr("GOAL");
		}
//		if(Board.isBlock(b)){
//			pr("BLOCK");
//		}
		if(Board.isCorner(b)){
			pr("CORNER");
		}
		if(Board.isCorridor(b)){
			pr("CORRIDOR");
		}
		pr("===== ====  ==== =====");

	}
// prints out all types of a byte
	static void whatAmI_GameState(byte b){
		pr("\n===== WHAT AM I? =====");
		if(GameState.isInvalid(b)){
			pr("INVALID");
		}
		if(GameState.isPlayer(b)){
			pr("PLAYER");
		}
		if(GameState.isBlock(b)){
			pr("BLOCK");
		}
		pr("===== ====  ==== =====");

	}

	static void whatAmI_Move(Move m){
		pr("\n===== WHAT AM I? =====");
		if(m.isNormal()){
			pr("NORMAL");
		}
		if(m.isPush()){
			pr("PUSH");
		}
		if(m.isNorth()){
			pr("NORTH");
		}
		if(m.isSouth()){
			pr("SOUTH");
		}
		if(m.isEast()){
			pr("EAST");
		}
		if(m.isWest()){
			pr("WEST");
		}
		pr("===== ====  ==== =====");
	}

	static void emptyStrings(String[][] s){
		for(int r = 0; r < s.length; r++)
			for(int c = 0; c < s[r].length; c++)
				s[r][c]="";
	}

	static void pr(Object msg){
		System.out.println(""+msg);
	}

	static int[] vectorClone(int[] source){
		int[] dest;
		dest=new int[source.length];
		System.arraycopy(source, 0, dest, 0, source.length);
		return dest;
	}

	static int[][] matrixClone(int[][] source){
		if(source.length<=0)
			return new int[0][0];
		int[][] dest = new int[source.length][source[0].length];
		for(int r = 0; r < source.length; r++){
			System.arraycopy(source[r], 0, dest[r], 0, source[r].length);
		}
		return dest;
	}

	static boolean[] vectorClone(boolean[] source){
		boolean[] dest;
		dest=new boolean[source.length];
		System.arraycopy(source, 0, dest, 0, source.length);
		return dest;
	}

	static boolean[][] matrixClone(boolean[][] source){
		if(source.length<=0)
			return new boolean[0][0];
		boolean[][] dest = new boolean[source.length][source[0].length];
		for(int r = 0; r < source.length; r++){
			System.arraycopy(source[r], 0, dest[r], 0, source[r].length);
		}
		return dest;
	}

    static boolean pathFromTo(Board b, GameState gs, int[] from, int[] to) {
//       int[] solutions = new int[1];
       ArrayList<DistNodeAStar> queue = new ArrayList<DistNodeAStar>();
       queue.add(new DistNodeAStar(0, from, 0, 0));

//       boolean[][] p = new boolean[b.mCellRows][b.mCellCols];
//       for (int i = 0; i < b.mCellRows; i++) {
//            for (int j = 0; j < b.mCellCols; j++) {
//                if (!b.isWall(i, j) && !b.isInvalid(i, j) && !gs.isBlock(gs.At(i, j))) {
//                    p[i][j] = true;
//                }
//            }
//       }

	   boolean[][] p = matrixClone(b.availableFligths2D);
	   for(int[] pos : gs.getBlockPoses()){
		   p[pos[0]][pos[1]] = false;
	   }

//       boolean[][] toThisPos = new boolean[b.mCellRows][b.mCellCols];
//       toThisPos[to[0]][to[1]] = true;

	   int[][] posOfEndPoints = new int[b.mCellRows][b.mCellCols];
	   posOfEndPoints[to[0]][to[1]] = 0;

       int solution = Move.findPathTo1Pos(queue, p, to, b, gs, Search.maxIter);
       if (solution >= 0) {
            return true;
       } else {
            return false;
       }
    }

	static int distFromTo(Board b, GameState gs, int[] from, int[] to, int maxDepth) {
       ArrayList<DistNodeAStar> queue = new ArrayList<DistNodeAStar>();
       queue.add(new DistNodeAStar(0, from, 0, 0));

	   boolean[][] p = matrixClone(b.availableFligths2D);
	   for(int[] pos : gs.getBlockPoses()){
		   p[pos[0]][pos[1]] = false;
	   }

	   int[][] posOfEndPoints = new int[b.mCellRows][b.mCellCols];
	   posOfEndPoints[to[0]][to[1]] = 0;

       return Move.findPathTo1Pos(queue, p, to, b, gs, maxDepth);
    }

	// TEST
//	static boolean pathFromTo(Board b, GameState gs, int[] from, int[] to) {
////       int[] solutions = new int[1];
//       ArrayList<DistNodeAStar> queue = new ArrayList<DistNodeAStar>();
//       queue.add(new DistNodeAStar(0, from, 0, 0));
//
//	   int[][] posOfEndPoints = new int[b.mCellRows][b.mCellCols];
//	   posOfEndPoints[to[0]][to[1]] = 0;
//
//       int solution = Move.findPathTo1Pos(queue, to, b, gs, Search.maxIter);
//       if (solution >= 0) {
//            return true;
//       } else {
//            return false;
//       }
//    }
//
//	static int distFromTo(Board b, GameState gs, int[] from, int[] to, int maxDepth) {
//       ArrayList<DistNodeAStar> queue = new ArrayList<DistNodeAStar>();
//       queue.add(new DistNodeAStar(0, from, 0, 0));
//
//	   int[][] posOfEndPoints = new int[b.mCellRows][b.mCellCols];
//	   posOfEndPoints[to[0]][to[1]] = 0;
//
//       return Move.findPathTo1Pos(queue, to, b, gs, maxDepth);
//    }

	static DistNodeAStar distNodeFromTo(Board b, GameState gs, int[] from, int[] to, int maxDepth) {
       ArrayList<DistNodeAStar> queue = new ArrayList<DistNodeAStar>();
       queue.add(new DistNodeAStar(0, from, 0, 0));

	   boolean[][] p = matrixClone(b.availableFligths2D);
	   for(int[] pos : gs.getBlockPoses()){
		   if(to[0] != pos[0] && to[1] != pos[1]){
			   p[pos[0]][pos[1]] = false;
		   }
	   }

	   int[][] posOfEndPoints = new int[b.mCellRows][b.mCellCols];
	   posOfEndPoints[to[0]][to[1]] = 0;

       return Move.findPathNodeTo1Pos(queue, p, to, b, gs, maxDepth);
    }
}
